home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 2 / Gold Medal Software Volume 2 (Gold Medal) (1994).iso / archive / ntzip.arj / FILEIO.C < prev    next >
C/C++ Source or Header  |  1993-10-08  |  49KB  |  1,778 lines

  1. /*
  2.  
  3.  Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
  4.  Permission is granted to any individual or institution to use, copy, or
  5.  redistribute this software so long as all of the original files are included
  6.  unmodified, that it is not sold for profit, and that this copyright notice
  7.  is retained.
  8.  
  9. */
  10.  
  11. /*
  12.  *  fileio.c by Mark Adler.
  13.     bug fix 10/93 by l kahn
  14.  */
  15.  
  16. #include "zip.h"
  17.  
  18. #include <time.h>
  19. #include <errno.h>
  20.  
  21. #ifdef WIN32
  22. #  include <sys\utime.h>
  23. #  include <malloc.h>
  24. #  ifdef MIPS
  25.      extern int _errno;
  26. #    define errno _errno
  27. #  endif
  28. #endif
  29. #ifdef S_IWUSR          /* For MINIX */
  30. #  ifdef S_IWRITE
  31. #    undef S_IWRITE
  32. #  endif /* S_IWRITE */
  33. #  define S_IWRITE S_IWUSR
  34. #endif /* S_IWUSR */
  35.  
  36. #ifdef MSDOS
  37. #  include <io.h>
  38. #  ifdef __TURBOC__
  39. #    include <dir.h>
  40. #  else /* !__TURBOC__ */
  41. #    include <direct.h>
  42. #  endif /* ?__TURBOC__ */
  43. #  define link rename
  44. #  ifdef OS2
  45. #    define MATCH shmatch
  46. #  else /* !OS2 */
  47. #    define MATCH dosmatch
  48. #  endif /* ?OS2 */
  49. #else /* !MSDOS */
  50.    extern int errno;    /* error number from system functions */
  51. #  ifdef VMS
  52. #    define RMDIR
  53. #    define link rename
  54. #  endif /* VMS */
  55. #  define MATCH shmatch
  56. #endif /* ?MSDOS */
  57.  
  58. #ifdef UTS
  59. #  define RMDIR
  60. #endif /* UTS */
  61.  
  62.  
  63. /* Extra malloc() space in names for cutpath() */
  64. #ifdef VMS
  65. #  define PAD 3         /* may have to change .FOO] to ]FOO.DIR */
  66. #else /* !VMS */
  67. #  define PAD 0
  68. #endif /* ?VMS */
  69.  
  70.  
  71. /* For now, assume DIRENT implies System V implies TERMIO */
  72. #ifdef DIRENT
  73. #  ifndef MINIX
  74. #    ifndef TERMIO
  75. #      define TERMIO
  76. #    endif /* !TERMIO */
  77. #  endif /* !MINIX */
  78. #endif /* DIRENT */
  79.  
  80.  
  81. #ifndef EXPORT
  82. #  ifdef MSVMS
  83. #    ifdef MSDOS
  84. #      include <conio.h>
  85. #    else /* !MSDOS */
  86. #      define getch() getc(stderr)
  87. #    endif /* ?MSDOS */
  88. #  else /* !MSVMS */
  89. #    ifdef TERMIO       /* Amdahl, Cray, all SysV? */
  90. #      ifdef CONVEX
  91. #        include <sys/termios.h>
  92. #        include <sgtty.h>
  93. #      else /* !CONVEX */
  94. #        include <sys/termio.h>
  95. #        define sgttyb termio
  96. #        define sg_flags c_lflag
  97. #      endif /* ?CONVEX */
  98.        int ioctl OF((int, int, voidp *));
  99. #      define GTTY(f,s) ioctl(f,TCGETA,s)
  100. #      define STTY(f,s) ioctl(f,TCSETAW,s)
  101. #    else /* !TERMIO */
  102. #      ifndef MINIX
  103. #        include <sys/ioctl.h>
  104. #      endif /* !MINIX */
  105. #      include <sgtty.h>
  106.        int gtty OF((int, struct sgttyb *));
  107.        int stty OF((int, struct sgttyb *));
  108. #      define GTTY gtty
  109. #      define STTY stty
  110. #    endif /* ?TERMIO */
  111.      int isatty OF((int));
  112.      char *ttyname OF((int));
  113.      int open OF((char *, int, ...));
  114.      int close OF((int));
  115.      int read OF((int, voidp *, int));
  116. #  endif /* ?MSVMS */
  117. #endif /* !EXPORT */
  118.  
  119.  
  120.  
  121. /* For directory access */
  122. #ifndef UTIL
  123. #ifdef DIRENT                   /* use getdents() */
  124. #  ifdef MINIX
  125. #    include <dirent.h>
  126. #  else /* !MINIX */
  127. #    include <sys/dirent.h>
  128. #  endif /* ?MINIX */
  129. #  define direct dirent
  130. #  ifdef MINIX
  131.      int getdents OF((int, char *, unsigned));
  132. #  else /* !MINIX */
  133.      int getdents OF((int, char *, int));
  134. #  endif /* ?MINIX */
  135. #  define DBSZ 4096     /* This has to be bigger than a directory block */
  136.    typedef struct {     /* directory stream buffer */
  137.      int f;             /* file descriptor for the directory "file" */
  138.      char *p;           /* pointer to next entry in buffer */
  139.      char *q;           /* pointer after end of buffer contents */
  140.      char b[DBSZ];              /* buffer */
  141.    } dstrm;
  142. #else /* !DIRENT */             /* use opendir(), etc. */
  143. #  ifdef CONVEX
  144. #    include <dirent.h>
  145. #    define direct dirent
  146. #  endif /* CONVEX */
  147. #  ifdef NDIR
  148. #    include "ndir.h"           /* for HPUX */
  149. #  else /* !NDIR */
  150. #    ifdef MSDOS
  151. #     ifdef OS2
  152. #      include "dir_os2.h"
  153. #     else /* !OS2 */
  154. #      include <dos.h>
  155. #      ifdef __TURBOC__
  156. #        define FATTR           FA_HIDDEN+FA_SYSTEM+FA_DIREC
  157. #        define FFIRST(n,d)     findfirst(n,(struct ffblk *)d,FATTR)
  158. #        define FNEXT(d)        findnext((struct ffblk *)d)
  159. #      elif WIN32
  160. #        define FATTR           FILE_ATTRIBUTE_HIDDEN+FILE_ATTRIBUTE_SYSTEM+FILE_ATTRIBUTE_DIRECTORY
  161. #      else /* !__TURBOC__ */
  162. #        define FATTR           _A_HIDDEN+_A_SYSTEM+_A_SUBDIR
  163. #        define FFIRST(n,d)     _dos_findfirst(n,FATTR,(struct find_t *)d)
  164. #        define FNEXT(d)        _dos_findnext((struct find_t *)d)
  165. #      endif /* ?__TURBOC__ */
  166. #ifdef WIN32
  167.  
  168.    /* l. kahn bug fix
  169.      because the d_name was too short here the strcpy failed on
  170.      an ntfs partition. increased from 14 to hand 130 char names */
  171.      
  172.        typedef struct direct {
  173.          char d_reserved[30];
  174.          char d_name[130];
  175.          int d_first;
  176.          HANDLE d_hFindFile;
  177.          } DIR;
  178. #else
  179.        typedef struct direct {
  180.          char d_reserved[30];
  181.          char d_name[13];
  182.          int d_first;
  183.        } DIR;
  184. #endif /* WIN32 */
  185. #     endif /* ?OS2 */
  186. #    else /* !MSDOS */
  187. #      ifdef VMS
  188. #        include <rms.h>
  189. #        include <ssdef.h>
  190. #        include <descrip.h>
  191.          typedef struct direct {
  192.              int d_wild;                /* flag for wildcard vs. non-wild */
  193.              struct FAB fab;
  194.              struct NAM nam;
  195.              char d_qualwildname[NAM$C_MAXRSS + 1];
  196.              char d_name[NAM$C_MAXRSS + 1];
  197.          } DIR;
  198. #      else /* !VMS */
  199. #        include <sys/dir.h>
  200. #        ifdef NODIR                    /* for AT&T 3B1 */
  201. #          define dirent direct
  202.            typedef FILE DIR;
  203. #          define dstrm DIR
  204. #        endif /* NODIR */
  205. #      endif /* ?VMS */
  206. #    endif /* ?MSDOS */
  207. #  endif /* ?NDIR */
  208. #  define dstrm DIR
  209. #  ifndef NODIR
  210.      DIR *opendir OF((char *));
  211. #  endif /* !NODIR */
  212. #  ifndef CONVEX
  213.      struct direct *readdir OF((DIR *));
  214. #  endif /* !CONVEX */
  215. #endif /* ?DIRENT */
  216. #endif /* !UTIL */
  217.  
  218.  
  219. /* Library functions not in (most) header files */
  220. char *mktemp OF((char *));
  221. int link OF((char *, char *));
  222. int unlink OF((char *));
  223. #ifndef CONVEX
  224. #  ifndef AIX
  225.      int chmod OF((char *, int));
  226. #  endif /* !AIX */
  227. #endif /* !CONVEX */
  228.  
  229.  
  230. #ifndef UTIL    /* the companion #endif is a bit of ways down ... */
  231.  
  232. #ifndef __TURBOC__
  233. #ifndef WIN32
  234.    int utime OF((char *, time_t *));
  235. #endif
  236. #endif /* !__TURBOC__ */
  237. #ifndef MSDOS
  238.    int open OF((char *, int, ...));
  239.    int close OF((int));
  240. #  ifndef RMDIR
  241.      int rmdir OF((char *));
  242. #  endif /* !RMDIR */
  243. #endif /* !MSDOS */
  244.  
  245.  
  246. /* Local globals (kinda like "military intelligence" or "broadcast quality") */
  247. local int exflag = 0;           /* Exclude flag */
  248.  
  249. /* Local functions */
  250. #ifdef PROTO
  251. #  ifdef VMS
  252.      local void vms_wild(char *, dstrm *);
  253. #  endif /* VMS */
  254. #  ifdef DIRENT
  255.      local dstrm *opend(char *);
  256.      local void closed(dstrm *);
  257. #  endif /* DIRENT */
  258.    local char *readd(dstrm *);
  259.    local int fqcmp(voidp *, voidp *);
  260.    local int fqcmpz(voidp *, voidp *);
  261.    local char *last(char *);
  262.    local char *msname(char *);
  263. #  ifdef VMS
  264.      local char *strlower(char *);
  265.      local char *strupper(char *);
  266. #  endif /* VMS */
  267.    local char *ex2in(char *);
  268.    local int newname(char *);
  269.    local void inctime(struct tm *);
  270.    local ulg unix2dostime(time_t *);
  271. #  ifndef __TURBOC__
  272.      local int cmptime(struct tm *, struct tm *);
  273.      local time_t invlocal(struct tm *);
  274. #  endif /* !__TURBOC__ */
  275. #endif /* PROTO */
  276.  
  277.  
  278.  
  279. #ifndef OS2
  280. #ifdef MSDOS
  281. dstrm *opendir(n)
  282. char *n;                /* directory to open */
  283. /* Start searching for files in the MSDOS directory n */
  284. {
  285. #ifndef WIN32
  286.   char  *p;              /* malloc'd temporary string */
  287. #endif
  288.  
  289.   dstrm *d;
  290.  
  291. #ifdef WIN32
  292.   WIN32_FIND_DATA fd;
  293.   DWORD dwAttr;
  294.   BOOL bAttr;
  295.  char p[256];
  296.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
  297.     printf("\nUnable to malloc dstrm\n");
  298. //  if (p = malloc(strlen(n) + 5) == NULL)
  299. //    printf("\nUnable to malloc p \n");
  300. //  strcpy(p, n);
  301. //  strcat(p, "\\*.*");
  302.   sprintf(p, "%s\\*.*", n);
  303. #else
  304.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
  305.       (p = malloc(strlen(n) + 5)) == NULL)
  306.   strcat(strcpy(p, n), "/*.*");
  307. #endif
  308.  
  309. #ifdef WIN32
  310.   if ((HANDLE)0xFFFFFFFF == (d->d_hFindFile = FindFirstFile(p, &fd)))
  311.      {
  312.      free((voidp *)p);
  313.      return NULL;
  314.      }
  315.   else
  316.      strcpy(d->d_name, fd.cFileName);
  317.   /* FindFirstFile does not do attribute based searches */
  318.   if (-1 != (dwAttr = GetFileAttributes(fd.cFileName)))
  319.      {
  320.      bAttr = FALSE;
  321.      if (FILE_ATTRIBUTE_SYSTEM == (dwAttr & FILE_ATTRIBUTE_SYSTEM))
  322.          bAttr = TRUE;
  323.      if (FILE_ATTRIBUTE_HIDDEN == (dwAttr & FILE_ATTRIBUTE_HIDDEN))
  324.          bAttr = TRUE;
  325.      if (FILE_ATTRIBUTE_DIRECTORY == (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
  326.          bAttr = TRUE;
  327.      if (!bAttr)
  328.          {
  329. #ifndef WIN32
  330.          free((voidp *)p);
  331. #endif
  332.          free ((void *) d);
  333.          return NULL;
  334.          }
  335.      }
  336. #else
  337.   if (FFIRST(p, d))
  338.   {
  339.     free((voidp *)p);
  340.     return NULL;
  341.   }
  342.   free((voidp *)p);
  343. #endif
  344.   d->d_first = 1;
  345.   return d;
  346. }
  347.  
  348. struct direct *readdir(d)
  349. dstrm *d;               /* directory stream to read from */
  350. /* Return pointer to first or next directory entry, or NULL if end. */
  351. {
  352. #ifdef WIN32
  353.   WIN32_FIND_DATA       fd;
  354. //  DWORD dwAttr;
  355. //  BOOL bAttr;
  356. #endif
  357.  
  358.   if (d->d_first)
  359.     d->d_first = 0;
  360.   else
  361. #ifdef WIN32
  362.   if (!FindNextFile(d->d_hFindFile, &fd))
  363.       return NULL;
  364.   else
  365.      strcpy(d->d_name, fd.cFileName);
  366.  
  367. /****
  368.   if (-1 != (dwAttr = GetFileAttributes(fd.cFileName)))
  369.      {
  370.      bAttr = FALSE;
  371.      if (FILE_ATTRIBUTE_SYSTEM == (dwAttr & FILE_ATTRIBUTE_SYSTEM))
  372.          bAttr = TRUE;
  373.      if (FILE_ATTRIBUTE_HIDDEN == (dwAttr & FILE_ATTRIBUTE_HIDDEN))
  374.          bAttr = TRUE;
  375.      if (FILE_ATTRIBUTE_DIRECTORY == (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
  376.          bAttr = TRUE;
  377.      if (!bAttr)
  378.          return (NULL);
  379.      }
  380.   else
  381.      return (NULL);
  382. ***/
  383. #else
  384.     if (FNEXT(d))
  385.       return NULL;
  386. #endif
  387.   return (struct direct *)d;
  388. }
  389. #ifdef WIN32
  390. void closedir(dstrm *d)
  391. {
  392.  
  393.     FindClose(d->d_hFindFile);
  394.  
  395.     return;
  396. }
  397. #else
  398. #  define closedir free
  399. #endif
  400. #endif /* MSDOS */
  401. #endif /* !OS2 */
  402.  
  403.  
  404.  
  405. #ifdef VMS
  406. /*---------------------------------------------------------------------------
  407.  
  408.     _vms_findfirst() and _vms_findnext(), based on public-domain DECUS C
  409.     fwild() and fnext() routines (originally written by Martin Minow, poss-
  410.     ibly modified by Jerry Leichter for bintnxvms.c), were written by Greg
  411.     Roelofs and are still in the public domain.  Routines approximate the
  412.     behavior of MS-DOS (MSC and Turbo C) findfirst and findnext functions.
  413.  
  414.   ---------------------------------------------------------------------------*/
  415. local void vms_wild(p, d)
  416. char *p;
  417. dstrm *d;
  418. {
  419.   /*
  420.    * Do wildcard setup
  421.    */
  422.   /* set up the FAB and NAM blocks. */
  423.   d->fab = cc$rms_fab;             /* initialize fab */
  424.   d->nam = cc$rms_nam;             /* initialize nam */
  425.  
  426.   d->fab.fab$l_nam = &d->nam;           /* fab -> nam */
  427.   d->fab.fab$l_fna = p;                 /* argument wild name */
  428.   d->fab.fab$b_fns = strlen(p);         /* length */
  429.  
  430.   d->nam.nam$l_esa = d->d_qualwildname; /* qualified wild name */
  431.   d->nam.nam$b_ess = NAM$C_MAXRSS;      /* max length */
  432.   d->nam.nam$l_rsa = d->d_name;         /* matching file name */
  433.   d->nam.nam$b_rss = NAM$C_MAXRSS;      /* max length */
  434.  
  435.   /* parse the file name */
  436.   if (sys$parse(&d->fab) != RMS$_NORMAL)
  437.     return -1;
  438.   /* Does this replace d->fab.fab$l_fna with a new string in its own space?
  439.      I sure hope so, since p is free'ed before this routine returns. */
  440.  
  441.   /* have qualified wild name (i.e., disk:[dir.subdir]*.*); null-terminate
  442.    * and set wild-flag */
  443.   d->d_qualwildname[d->nam.nam$b_esl] = '\0';
  444.   d->d_wild = (d->nam.nam$l_fnb & NAM$M_WILDCARD)? 1 : 0;   /* not used... */
  445. #ifdef DEBUG
  446.   printf("  incoming wildname:  %s\n", p);
  447.   printf("  qualified wildname:  %s\n", d->d_qualwildname);
  448. #endif /* DEBUG */
  449. }
  450.  
  451. dstrm *opendir(n)
  452. char *n;                /* directory to open */
  453. /* Start searching for files in the VMS directory n */
  454. {
  455.   char *c;              /* scans VMS path */
  456.   dstrm *d;             /* malloc'd return value */
  457.   int m;                /* length of name */
  458.   char *p;              /* malloc'd temporary string */
  459.  
  460.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
  461.       (p = malloc((m = strlen(n)) + 4)) == NULL)
  462.     return NULL;
  463.   /* Directory may be in form "[DIR.SUB1.SUB2]" or "[DIR.SUB1]SUB2.DIR;1".
  464.      If latter, convert to former. */
  465.   if (m > 0  &&  *(c = strcpy(p,n)+m-1) != ']')
  466.   {
  467.     while (--c > p  &&  *c != ';')
  468.       ;
  469.     if (c-p < 5  ||  strncmp(c-4, ".DIR", 4))
  470.     {
  471.       free((voidp *)d);  free((voidp *)p);
  472.       return NULL;
  473.     }
  474.     c -= 3;
  475.     *c-- = '\0';        /* terminate at "DIR;#" */
  476.     *c = ']';           /* "." --> "]" */
  477.     while (c > p  &&  *--c != ']')
  478.       ;
  479.     *c = '.';           /* "]" --> "." */
  480.   }
  481.   strcat(p, "*.*");
  482.   vms_wild(p, d);       /* set up wildcard */
  483.   free((voidp *)p);
  484.   return d;
  485. }
  486.  
  487. struct direct *readdir(d)
  488. dstrm *d;               /* directory stream to read from */
  489. /* Return pointer to first or next directory entry, or NULL if end. */
  490. {
  491.   int r;                /* return code */
  492.  
  493.   do {
  494.     d->fab.fab$w_ifi = 0;       /* internal file index:  what does this do? */
  495.  
  496.     /* get next match to possible wildcard */
  497.     if ((r = sys$search(&d->fab)) == RMS$_NORMAL)
  498.     {
  499.         d->d_name[d->nam.nam$b_rsl] = '\0';   /* null terminate */
  500.         return (struct direct *)d;   /* OK */
  501.     }
  502.   } while (r == RMS$_PRV);
  503.   return NULL;
  504. }
  505. #  define closedir free
  506. #endif /* VMS */
  507.  
  508.  
  509. #ifdef NODIR                    /* for AT&T 3B1 */
  510. /*
  511. **  Apparently originally by Rich Salz.
  512. **  Cleaned up and modified by James W. Birdsall.
  513. */
  514.  
  515. #  define opendir(path) fopen(path, "r")
  516.  
  517. struct direct *readdir(dirp)
  518. DIR *dirp;
  519. {
  520.   static struct direct entry;
  521.  
  522.   if (dirp == NULL) 
  523.     return NULL;
  524.   for (;;)
  525.     if (fread (&entry, sizeof (struct direct), 1, dirp) == 0) 
  526.       return NULL;
  527.     else if (entry.d_ino) 
  528.       return (&entry);
  529. } /* end of readdir() */
  530.  
  531. #  define closedir(dirp) fclose(dirp)
  532. #endif /* NODIR */
  533.  
  534.  
  535. #ifdef DIRENT
  536. local dstrm *opend(n)
  537. char *n;                /* directory name to open */
  538. /* Open the directory *n, returning a pointer to an allocated dstrm, or
  539.    NULL if error. */
  540. {
  541.   dstrm *d;             /* pointer to malloc'ed directory stream */
  542.  
  543.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
  544.     return NULL;
  545.   if ((d->f = open(n, 0, 0)) < 0)               /* open directory */
  546.     return NULL;
  547.   d->p = d->q = d->b;                           /* buffer is empty */
  548.   return d;
  549. }
  550. #else /* !DIRENT */
  551. #  define opend opendir                         /* just use opendir() */
  552. #endif /* ?DIRENT */
  553.  
  554.  
  555. local char *readd(d)
  556. dstrm *d;               /* directory stream to read from */
  557. /* Return a pointer to the next name in the directory stream d, or NULL if
  558.    no more entries or an error occurs. */
  559. {
  560.   struct direct *e;     /* directory entry read */
  561.  
  562. #ifdef DIRENT
  563.   int n;                /* number of entries read by getdents */
  564.  
  565.   if (d->p >= d->q)                             /* if empty, fill buffer */
  566.     if ((n = getdents(d->f, d->b, DBSZ)) <= 0)
  567.       return NULL;
  568.     else
  569.       d->q = n + (d->p = d->b);
  570.   e = (struct direct *)(d->p);                  /* point to entry */
  571.   d->p += ((struct direct *)(d->p))->d_reclen;  /* advance */
  572.   return e->d_name;                             /* return name */
  573. #else /* !DIRENT */
  574.   return (e = readdir(d)) == NULL ? (char *)NULL : e->d_name;
  575. #endif /* ?DIRENT */
  576. }
  577.  
  578.  
  579. #ifdef DIRENT
  580. local void closed(d)
  581. dstrm *d;               /* directory stream to close */
  582. /* Close the directory stream */
  583. {
  584.   close(d->f);
  585.   free((voidp *)d);
  586. }
  587. #else /* !DIRENT */
  588. #  define closed closedir
  589. #endif /* ?DIRENT */
  590.  
  591.  
  592. #ifdef MSDOS
  593. int wild(p)
  594. char *p;                /* path/pattern to match */
  595. /* If not in exclude mode, expand the pattern based on the contents of the
  596.    file system.  Return an error code in the ZE_ class. */
  597. {
  598.   dstrm *d;             /* stream for reading directory */
  599.   char *e;              /* name found in directory */
  600.   int f;                /* true if there was a match */
  601.   char *n;              /* constructed name from directory */
  602.   char *q;              /* temporary variable */
  603.   int r;                /* temporary variable */
  604.   char v[4];            /* space for device current directory */
  605.  
  606.   /* If excluding, don't bother with file system */
  607.   if (exflag)
  608.     return procname(p);
  609.   /* Normalize pattern to upper case, path delimiter as '/'. */
  610. #if !defined(OS2) && !defined(WIN32)
  611.   strupr(p);                            /* convert to upper case */
  612. #endif /* !OS2 */
  613.   for (q = p; *q; q++)                  /* use / consistently */
  614.     if (*q == '\\')
  615.       *q = '/';
  616.  
  617.   /* Only name can have special matching characters */
  618.   if ((q = isshexp(p)) != NULL &&
  619.       (strrchr(q, '/') != NULL || strrchr(q, ':') != NULL))
  620.     return ZE_PARMS;
  621.   /* Separate path and name */
  622.   if ((q = strrchr(p, '/')) != NULL)
  623.     *q++ = 0;
  624.   else if (*p && *(p+1) == ':')
  625.   {
  626.     q = p + 2;
  627.     v[0] = *p;
  628.     strcpy(v+1, ":.");
  629.     p = v;
  630.   }
  631.   else
  632.   {
  633.     q = p;
  634.     p = ".";
  635.   }
  636.   if (*p == 0)
  637.     p = "/";
  638.  
  639.   /* Search that level for matching names */
  640.   if ((d = opend(p)) == NULL)
  641.     return ZE_MISS;
  642.   if (strcmp(p+1, ":.") == 0)
  643.     *(p+2) = 0;
  644.   f = 0;
  645.   while ((e = readd(d)) != NULL)
  646.     if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e))
  647.     {
  648.       f = 1;
  649.       if (strcmp(p, ".") == 0)
  650.         procname(e);
  651.       else if (*p && strcmp(p+1, ":") == 0)
  652.       {
  653.         if ((n = malloc(strlen(e) + 3)) == NULL)
  654.           return ZE_MEM;
  655.         r = procname(strcat(strcpy(n, p), e));
  656.         free((voidp *)n);
  657.         if (r)
  658.           return r;
  659.       }
  660.       else
  661.       {
  662.         if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
  663.           return ZE_MEM;
  664.         if (strcmp(p, "/"))
  665.           strcpy(n, p);
  666.         else
  667.           *n = 0;
  668.         r = procname(strcat(strcat(n, "/"), e));
  669.         free((voidp *)n);
  670.         if (r)
  671.           return r;
  672.       }
  673.     }
  674.   closed(d);
  675.  
  676.   /* Done */
  677.   return f ? ZE_OK : ZE_MISS;
  678. }
  679. #endif /* MSDOS */
  680.  
  681.  
  682. #ifdef VMS
  683. int wild(p)
  684. char *p;                /* path/pattern to match */
  685. /* Expand the pattern based on the contents of the file system.  Return an
  686.    error code in the ZE_ class. */
  687. {
  688.   dstrm *d;             /* stream for reading directory */
  689.   char *e;              /* name found in directory */
  690.   int f;                /* true if there was a match */
  691.  
  692.   /* Search given pattern for matching names */
  693.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
  694.     return ZE_MEM;
  695.   vms_wild(p, d);       /* pattern may be more than just directory name */
  696.   f = 0;
  697.   while ((e = readd(d)) != NULL)        /* "dosmatch" is already built in */
  698.     if (procname(e) == ZE_OK)
  699.       f = 1;
  700.   closed(d);
  701.  
  702.   /* Done */
  703.   return f ? ZE_OK : ZE_MISS;
  704. }
  705. #endif /* VMS */
  706.  
  707.  
  708. char *getnam(n)
  709. char *n;                /* where to put name (must have >=FNMAX+1 bytes) */
  710. /* Read a space, \n, \r, or \t delimited name from stdin into n, and return
  711.    n.  If EOF, then return NULL.  Also, if the name read is too big, return
  712.    NULL. */
  713. {
  714.   int c;                /* last character read */
  715.   char *p;              /* pointer into name area */
  716.  
  717.   p = n;
  718.   while ((c = getchar()) == ' ' || c == '\n' || c == '\r' || c == '\t')
  719.     ;
  720.   if (c == EOF)
  721.     return NULL;
  722.   do {
  723.     if (p - n >= FNMAX)
  724.       return NULL;
  725.     *p++ = (char)c;
  726.     c = getchar();
  727.   } while (c != EOF && c != ' ' && c != '\n' && c != '\r' && c != '\t');
  728.   *p = 0;
  729.   return n;
  730. }
  731.  
  732.  
  733. struct flist far *fexpel(f)
  734. struct flist far *f;    /* entry to delete */
  735. /* Delete the entry *f in the doubly-linked found list.  Return pointer to
  736.    next entry to allow stepping through list. */
  737. {
  738.   struct flist far *t;  /* temporary variable */
  739.  
  740.   t = f->nxt;
  741.   *(f->lst) = t;                        /* point last to next, */
  742.   if (t != NULL)
  743.     t->lst = f->lst;                    /* and next to last */
  744.   if (f->name != NULL)                  /* free memory used */
  745.     free((voidp *)(f->name));
  746.   if (f->zname != NULL)
  747.     free((voidp *)(f->zname));
  748.   farfree((voidp far *)f);
  749.   fcount--;                             /* decrement count */
  750.   return t;                             /* return pointer to next */
  751. }
  752.  
  753.  
  754. local int fqcmp(a, b)
  755. voidp *a, *b;           /* pointers to pointers to found entries */
  756. /* Used by qsort() to compare entries in the found list by name. */
  757. {
  758.   return strcmp((*(struct flist far **)a)->name,
  759.                 (*(struct flist far **)b)->name);
  760. }
  761.  
  762.  
  763. local int fqcmpz(a, b)
  764. voidp *a, *b;           /* pointers to pointers to found entries */
  765. /* Used by qsort() to compare entries in the found list by zname. */
  766. {
  767.   return strcmp((*(struct flist far **)a)->zname,
  768.                 (*(struct flist far **)b)->zname);
  769. }
  770.  
  771.  
  772. local char *last(p)
  773. char *p;                /* sequence of / delimited path components */
  774. /* Return a pointer to the start of the last path component. */
  775. {
  776.   char *t;              /* temporary variable */
  777.  
  778. #ifdef VMS
  779.   if ((t = strrchr(p, ']')) != NULL)
  780. #else /* !VMS */
  781.   if ((t = strrchr(p, '/')) != NULL)
  782. #endif /* ?VMS */
  783.     return t + 1;
  784.   else
  785.     return p;
  786. }
  787.  
  788.  
  789. #define TOUP(c) ((c) >= 'a' && (c) <= 'z' ? (c)-'a'+'A' : (c))
  790.  
  791. local char *msname(n)
  792. char *n;
  793. /* Reduce all path components to MSDOS upper case 8.3 style names.  Probably
  794.    should also check for invalid characters, but I don't know which ones
  795.    those are. */
  796. {
  797.   int c;                /* current character */
  798.   int f;                /* characters in current component */
  799.   char *p;              /* source pointer */
  800.   char *q;              /* destination pointer */
  801.  
  802.   p = q = n;
  803.   f = 0;
  804.   while ((c = *p++) != 0)
  805.     if (c == '/')
  806.     {
  807.       *q++ = (char)c;
  808.       f = 0;                            /* new component */
  809.     }
  810.     else if (c == '.')
  811.       if (f < 9)
  812.       {
  813.         *q++ = (char)c;
  814.         f = 9;                          /* now in file type */
  815.       }
  816.       else
  817.         f = 12;                         /* now just excess characters */
  818.     else
  819.       if (f < 12 && f != 8)
  820.       {
  821.         *q++ = (char)(TOUP(c));
  822.         f++;                            /* do until end of name or type */
  823.       }
  824.   *q = 0;
  825.   return n;
  826. }
  827.  
  828.  
  829. #ifdef VMS
  830. local char *strlower(s)
  831. char *s;                /* string to convert */
  832. /* Convert all uppercase letters to lowercase in string s */
  833. {
  834.   char *p;              /* scans string */
  835.  
  836.   for (p = s; *p; p++)
  837.     if (*p >= 'A' && *p <= 'Z')
  838.       *p += 'a' - 'A';
  839.   return s;
  840. }
  841.  
  842. local char *strupper(s)
  843. char *s;                /* string to convert */
  844. /* Convert all lowercase letters to uppercase in string s */
  845. {
  846.   char *p;              /* scans string */
  847.  
  848.   for (p = s; *p; p++)
  849.     if (*p >= 'a' && *p <= 'a')
  850.       *p -= 'a' - 'A';
  851.   return s;
  852. }
  853. #endif /* VMS */
  854.  
  855.  
  856. local char *ex2in(x)
  857. char *x;                /* external file name */
  858. /* Convert the external file name to a zip file name, returning the malloc'ed
  859.    string or NULL if not enough memory. */
  860. {
  861.   char *n;              /* internal file name (malloc'ed) */
  862.   char *t;              /* shortened name */
  863.  
  864.   /* Find starting point in name before doing malloc */
  865. #ifdef MSDOS                            /* msdos */
  866.   t = *x && *(x + 1) == ':' ? x + 2 : x;
  867.   while (*t == '/' || *t == '\\')
  868.     t++;
  869. #else /* !MSDOS */
  870. #  ifdef VMS                            /* vms */
  871.   t = x;
  872.   if ((n = strrchr(t, ':')) != NULL)
  873.     t = n + 1;
  874.   if (*t == '[' && (n = strrchr(t, ']')) != NULL)
  875.     if ((x = strchr(t, '.')) != NULL && x < n)
  876.       t = x + 1;
  877.     else
  878.       t = n + 1;
  879. #  else /* !VMS */                      /* unix */
  880.   for (t = x; *t == '/'; t++)
  881.     ;
  882. #  endif /* ?VMS */
  883. #endif /* ?MSDOS */
  884.   if (!pathput)
  885.     t = last(t);
  886.  
  887.   /* Malloc space for internal name and copy it */
  888.   if ((n = malloc(strlen(t) + 1)) == NULL)
  889.     return NULL;
  890.   strcpy(n, t);
  891.  
  892.   /* Make changes, if any, to the copied name (leave original intact) */
  893. #ifdef MSDOS
  894.   for (t = n; *t; t++)
  895.     if (*t == '\\')
  896.       *t = '/';
  897. #endif /* MSDOS */
  898. #ifdef VMS
  899.   if ((t = strrchr(n, ']')) != NULL)
  900.   {
  901.     *t = '/';
  902.     while (--t > n)
  903.       if (*t == '.')
  904.         *t = '/';
  905.   }
  906.  
  907.   /* Fix from Greg Roelofs: */
  908.   /* Get current working directory and strip from n (t now = n) */
  909.   {
  910.     char cwd[256], *p, *q;
  911.     int c;
  912.  
  913.     if (getcwd(cwd, 256) && ((p = strchr(cwd, '.')) != NULL))
  914.     {
  915.       ++p;
  916.       if ((q = strrchr(p, ']')) != NULL)
  917.       {
  918.         *q = '/';
  919.         while (--q > p)
  920.           if (*q == '.')
  921.             *q = '/';
  922.         /* strip bogus path parts from n */
  923.         if (strncmp(n, p, (c=strlen(p))) == 0)
  924.         {
  925.           q = n + c;
  926.           while (*t++ = *q++)
  927.             ;
  928.         }
  929.       }
  930.     }
  931.   }
  932.   strlower(n);
  933.   if (!vmsver)
  934.     if ((t = strrchr(n, ';')) != NULL)
  935.       *t = 0;
  936. #endif /* VMS */
  937.   if (dosify)
  938.     msname(n);
  939.  
  940.   /* Returned malloc'ed name */
  941.   return n;
  942. }
  943.  
  944.  
  945. char *in2ex(n)
  946. char *n;                /* internal file name */
  947. /* Convert the zip file name to an external file name, returning the malloc'ed
  948.    string or NULL if not enough memory. */
  949. {
  950.   char *x;              /* external file name */
  951. #ifdef VMS
  952.   char *t;              /* scans name */
  953.  
  954.   if ((t = strrchr(n, '/')) == NULL)
  955. #endif /* VMS */
  956.   {
  957.     if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
  958.       return NULL;
  959.     strcpy(x, n);
  960.   }
  961. #ifdef VMS
  962.   else
  963.   {
  964.     if ((x = malloc(strlen(n) + 3 + PAD)) == NULL)
  965.       return NULL;
  966.     strcpy(x, "[.");
  967.     strcpy(x + 2, n);
  968.     *(t = x + 2 + (t - n)) = ']';
  969.     while (--t > x)
  970.       if (*t == '/')
  971.         *t = '.';
  972.   }
  973.   strupper(x);
  974. #endif /* VMS */
  975.   return x;
  976. }
  977.  
  978.  
  979. int exclude()
  980. /* Change from including to excluding names when procname() called.  Return
  981.    an error code in the ZE_ class. */
  982. {
  983.   struct flist far *f;          /* steps through found linked list */
  984.   int j;                        /* index for s */
  985.   struct flist far **s;         /* sorted table */
  986.  
  987.   /* sort found list, remove duplicates */
  988.   if (fcount)
  989.   {
  990.     if ((s = (struct flist far **)malloc(
  991.          fcount * sizeof(struct flist far *))) == NULL)
  992.       return ZE_MEM;
  993.     for (j = 0, f = found; f != NULL; f = f->nxt)
  994.       s[j++] = f;
  995.     qsort((char *)s, fcount, sizeof(struct flist far *), fqcmp);
  996.     for (j = fcount - 1; j > 0; j--)
  997.       if (strcmp(s[j - 1]->name, s[j]->name) == 0)
  998.         fexpel(s[j]);           /* fexpel() changes fcount */
  999.     qsort((char *)s, fcount, sizeof(struct flist far *), fqcmpz);
  1000.     for (j = 1; j < fcount; j++)
  1001.       if (strcmp(s[j - 1]->zname, s[j]->zname) == 0)
  1002.       {
  1003.         warn("name in zip file repeated: ", s[j]->zname);
  1004.         warn("  first full name: ", s[j - 1]->name);
  1005.         warn(" second full name: ", s[j]->name);
  1006.         return ZE_PARMS;
  1007.       }
  1008.     free((voidp *)s);
  1009.   }
  1010.   exflag = 1;
  1011.   return ZE_OK;
  1012. }
  1013.  
  1014.  
  1015. local int newname(n)
  1016. char *n;                /* name to add (or exclude) */
  1017. /* Add (or exclude) a name that is not in the zip file.  Return an error
  1018.    code in the ZE_ class. */
  1019. {
  1020.   char *m;
  1021.   struct flist far *f;  /* where in found, or new found entry */
  1022.   struct zlist far *z;  /* where in zfiles (if found) */
  1023.  
  1024.   /* Search for name in zip file.  If there, mark it, else add to
  1025.      list of new names to do (or remove from that list). */
  1026.   if ((m = ex2in(n)) == NULL)
  1027.     return ZE_MEM;
  1028.   if ((z = zsearch(m)) != NULL)
  1029.     if (exflag)
  1030.     {
  1031.       z->mark = 0;
  1032.       free((voidp *)m);
  1033.       if (verbose)
  1034.         printf("zip diagnostic: excluding %s\n", z->name);
  1035.     }
  1036.     else
  1037.     {
  1038.       free((voidp *)(z->name));
  1039.       free((voidp *)(z->zname));
  1040.       if ((z->name = malloc(strlen(n) + 1 + PAD)) == NULL)
  1041.         return ZE_MEM;
  1042.       strcpy(z->name, n);
  1043.       z->zname = m;
  1044.       z->mark = 1;
  1045.       if (verbose)
  1046.         printf("zip diagnostic: including %s\n", z->name);
  1047.     }
  1048.   else
  1049.     if (exflag)
  1050.     {
  1051.       /* search list for name--if there, remove it */
  1052.       for (f = found; f != NULL; f = f->nxt)
  1053.         if (strcmp(n, f->name) == 0)
  1054.         {
  1055.           fexpel(f);
  1056.           break;
  1057.         }
  1058.       free((voidp *)m);
  1059.     }
  1060.     else
  1061.     {
  1062.       /* allocate space and add to list */
  1063.       if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
  1064.           (f->name = malloc(strlen(n) + 1 + PAD)) == NULL)
  1065.       {
  1066.         if (f != NULL)
  1067.           farfree((voidp far *)f);
  1068.         return ZE_MEM;
  1069.       }
  1070.       strcpy(f->name, n);
  1071.       f->zname = m;
  1072.       *fnxt = f;
  1073.       f->lst = fnxt;
  1074.       f->nxt = NULL;
  1075.       fnxt = &f->nxt;
  1076.       fcount++;
  1077.     }
  1078.   return ZE_OK;
  1079. }
  1080.  
  1081.  
  1082. int procname(n)
  1083. char *n;                /* name to process */
  1084. /* Process a name or sh expression to operate on (or exclude).  Return
  1085.    an error code in the ZE_ class. */
  1086. {
  1087.   char *a;              /* path and name for recursion */
  1088.   dstrm *d;             /* directory stream from opend() */
  1089.   char *e;              /* pointer to name from readd() */
  1090.   struct flist far *f;  /* steps through found list */
  1091.   int m;                /* matched flag */
  1092.   char *p;              /* path for recursion */
  1093.   struct stat s;        /* result of stat() */
  1094.   struct zlist far *z;  /* steps through zfiles list */
  1095.  
  1096.   if (
  1097. #ifdef S_IFLNK          /* if symbolic links exist ... */
  1098.       linkput ? lstat(n, &s) :
  1099. #endif /* S_IFLNK */
  1100.       stat(n, &s)
  1101. #ifdef __TURBOC__       /* Borland bug: stat() succeeds on wild card names! */
  1102.       || isshexp(n)
  1103. #endif /* __TURBOC__ */
  1104.      )
  1105.   {
  1106.     /* Not a file--search for shell expression in zip file */
  1107.     p = ex2in(n);               /* shouldn't affect matching chars */
  1108.     m = 1;
  1109.     for (z = zfiles; z != NULL; z = z->nxt)
  1110.       if (MATCH(p, z->zname))
  1111.       {
  1112.         z->mark = !exflag;
  1113.         if (verbose)
  1114.           printf("zip diagnostic: %scluding %s\n",
  1115.                  exflag ? "ex" : "in", z->name);
  1116.         m = 0;
  1117.       }
  1118.     /* If excluding, also search for expression in found list */
  1119.     if (exflag)
  1120.     {
  1121.       for (f = found; f != NULL;)
  1122.         if (MATCH(p, f->zname))
  1123.         {
  1124.           f = fexpel(f);
  1125.           m = 0;
  1126.         }
  1127.         else
  1128.           f = f->nxt;
  1129.     }
  1130.     free((voidp *)p);
  1131.     if (m)
  1132.       return ZE_MISS;           /* no match */
  1133.   }
  1134.   else
  1135.   {
  1136.     /* Live name--use if file, recurse if directory */
  1137. #ifdef MSDOS
  1138. #if !defined(OS2) && !defined(WIN32)
  1139.     strupr(n);                  /* convert to upper case */
  1140. #endif /* !OS2 */
  1141.     for (p = n; *p; p++)        /* use / consistently */
  1142.       if (*p == '\\')
  1143.         *p = '/';
  1144. #endif /* MSDOS */
  1145.     switch (s.st_mode & S_IFMT)
  1146.     {
  1147.       case S_IFREG:             /* add or remove name of file */
  1148. #ifdef S_IFLNK
  1149.       case S_IFLNK:
  1150. #endif /* S_IFLNK */
  1151.         if ((m = newname(n)) != ZE_OK)
  1152.           return m;
  1153.         break;
  1154.       case S_IFDIR:             /* recurse into directory */
  1155.         if (recurse && (d = opend(n)) != NULL)
  1156.         {
  1157. #ifdef VMS
  1158.           while ((e = readd(d)) != NULL)
  1159.             if ((m = procname(e)) != ZE_OK)     /* recurse on name */
  1160.             {
  1161.               /* want to just set warning error and continue */
  1162.               closed(d);
  1163.               return m;
  1164.             }
  1165. #else /* !VMS */
  1166.           if ((p = malloc(strlen(n)+2)) == NULL)
  1167.             return ZE_MEM;
  1168.           if (strcmp(n, ".") == 0)
  1169.             *p = 0;                     /* avoid "./" prefix */
  1170.           else
  1171.           {
  1172.             strcpy(p, n);
  1173.             a = p + strlen(p);
  1174.             if (a[-1] != '/')
  1175.               strcpy(a, "/");
  1176.           }
  1177.           while ((e = readd(d)) != NULL)
  1178.             if (strcmp(e, ".") && strcmp(e, ".."))
  1179.             {
  1180.               if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
  1181.               {
  1182.                 free((voidp *)p);
  1183.                 closed(d);
  1184.                 return ZE_MEM;
  1185.               }
  1186.               strcat(strcpy(a, p), e);
  1187.               if ((m = procname(a)) != ZE_OK)   /* recurse on name */
  1188.               {
  1189.                 free((voidp *)a);  free((voidp *)p);
  1190.                 closed(d);
  1191.                 return m;
  1192.               }
  1193.               free((voidp *)a);
  1194.             }
  1195.           free((voidp *)p);
  1196. #endif /* ?VMS */
  1197.           closed(d);
  1198.         }
  1199.       }
  1200.     }
  1201.   return ZE_OK;
  1202. }
  1203.  
  1204.  
  1205. #ifndef __TURBOC__
  1206. local int cmptime(p, q)
  1207. struct tm *p, *q;       /* times to compare */
  1208. /* Return negative if time p is before time q, positive if after, and
  1209.    zero if the same */
  1210. {
  1211.   int r;                /* temporary variable */
  1212.  
  1213.   if ((r = p->tm_year - q->tm_year) != 0)
  1214.     return r;
  1215.   else if ((r = p->tm_mon - q->tm_mon) != 0)
  1216.     return r;
  1217.   else if ((r = p->tm_mday - q->tm_mday) != 0)
  1218.     return r;
  1219.   else if ((r = p->tm_hour - q->tm_hour) != 0)
  1220.     return r;
  1221.   else if ((r = p->tm_min - q->tm_min) != 0)
  1222.     return r;
  1223.   else
  1224.     return p->tm_sec - q->tm_sec;
  1225. }
  1226.  
  1227.  
  1228. local time_t invlocal(t)
  1229. struct tm *t;           /* time to convert */
  1230. /* Find inverse of localtime() using bisection.  This routine assumes that
  1231.    time_t is an integer type, either signed or unsigned.  The expectation
  1232.    is that sometime before the year 2038, time_t will be made a 64-bit
  1233.    integer, and this routine will still work. */
  1234. {
  1235.   time_t i;             /* midpoint of current root range */
  1236.   time_t l;             /* lower end of root range */
  1237.   time_t u;             /* upper end of root range */
  1238.  
  1239.   /* Bracket the root [0,largest time_t].  Note: if time_t is a 32-bit signed
  1240.      integer, then the upper bound is GMT 1/19/2038 03:14:07, after which all
  1241.      the Unix systems in the world come to a grinding halt.  Either that, or
  1242.      all those systems will suddenly find themselves transported to December
  1243.      of 1901 ... */
  1244.   l = 0;
  1245.   u = 1;
  1246.   while (u < (u << 1))
  1247.     u = (u << 1) + 1;
  1248.  
  1249.   /* Find the root */
  1250.   while (u - l > 1)
  1251.   {
  1252.     i = l + ((u - l) >> 1);
  1253.     if (cmptime(localtime(&i), t) <= 0)
  1254.       l = i;
  1255.     else
  1256.       u = i;
  1257.   }
  1258.   return l;
  1259. }
  1260. #endif /* !__TURBOC__ */
  1261.  
  1262.  
  1263. void stamp(f, d)
  1264. char *f;                /* name of file to change */
  1265. ulg d;                  /* dos-style time to change it to */
  1266. /* Set last updated and accessed time of file f to the DOS time d. */
  1267. {
  1268. #ifdef __TURBOC__
  1269.   int h;                /* file handle */
  1270.  
  1271.   if ((h = open(f, 0)) != -1)
  1272.   {
  1273.     setftime(h, (struct ftime *)&d);
  1274.     close(h);
  1275.   }
  1276. #else /* !__TURBOC__ */
  1277. #ifdef VMS
  1278.   warn("timestamp not implemented yet under VMS", "");
  1279. #else /* !VMS */
  1280.   struct tm t;          /* argument for invlocal() */
  1281. #ifdef WIN32
  1282.   struct utimbuf u;
  1283. #else
  1284.   time_t u[2];          /* argument for utime() */
  1285. #endif
  1286.   /* Convert DOS time to time_t format in u[0] and u[1] */
  1287.   t.tm_sec = (int)(d << 1) & 0x3e;
  1288.   t.tm_min = (int)(d >> 5) & 0x3f;
  1289.   t.tm_hour = (int)(d >> 11) & 0x1f;
  1290.   t.tm_mday = (int)(d >> 16) & 0x1f;
  1291.   t.tm_mon = ((int)(d >> 21) & 0xf) - 1;
  1292.   t.tm_year = ((int)(d >> 25) & 0x7f) + 80;
  1293. #ifdef WIN32
  1294.   u.modtime = u.actime = invlocal(&t);
  1295. #else
  1296.   u[0] = u[1] = invlocal(&t);
  1297. #endif
  1298.   /* Set updated and accessed times of f */
  1299.   utime(f, &u);
  1300. #endif /* ?VMS */
  1301. #endif /* ?__TURBOC__ */
  1302. }
  1303.  
  1304.  
  1305. local void inctime(s)
  1306. struct tm *s;           /* time to increment in place */
  1307. /* Increment the time structure *s by one second, return the result in
  1308.    place. */
  1309. {
  1310.   int y;                /* temporary variable */
  1311.  
  1312.   /* days in each month, except for February */
  1313.   static int days[] = {31,0,31,30,31,30,31,31,30,31,30,31};
  1314.  
  1315.   /* Set days in February from year (1900 is a leap year, 2000 is not) */
  1316.   y = s->tm_year + 1900;
  1317.   days[1] = y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) ? 29 : 28;
  1318.  
  1319.   /* Increment time with carry */
  1320.   if (s->tm_sec != 59)
  1321.     s->tm_sec++;
  1322.   else if (s->tm_sec = 0, s->tm_min != 59)
  1323.     s->tm_min++;
  1324.   else if (s->tm_min = 0, s->tm_hour != 23)
  1325.     s->tm_hour++;
  1326.   else if (s->tm_hour = 0, s->tm_mday != days[s->tm_mon])
  1327.     s->tm_mday++;
  1328.   else if (s->tm_mday = 1, s->tm_mon != 11)
  1329.     s->tm_mon++;
  1330.   else
  1331.   {
  1332.     s->tm_mon = 0;
  1333.     s->tm_year++;
  1334.   }
  1335. }
  1336.  
  1337.  
  1338. ulg dostime(y, n, d, h, m, s)
  1339. int y;                  /* year */
  1340. int n;                  /* month */
  1341. int d;                  /* day */
  1342. int h;                  /* hour */
  1343. int m;                  /* minute */
  1344. int s;                  /* second */
  1345. /* Convert the date y/n/d and time h:m:s to a four byte DOS date and
  1346.    time (date in high two bytes, time in low two bytes allowing magnitude
  1347.    comparison). */
  1348. {
  1349.   return y < 1980 ? dostime(1980, 1, 1, 0, 0, 0) :
  1350.         (((ulg)y - 1980) << 25) | ((ulg)n << 21) | ((ulg)d << 16) |
  1351.         ((ulg)h << 11) | ((ulg)m << 5) | ((ulg)s >> 1);
  1352. }
  1353.  
  1354.  
  1355. local ulg unix2dostime(t)
  1356. time_t *t;              /* unix time to convert */
  1357. /* Return the Unix time t in DOS format, rounded up to the next two
  1358.    second boundary. */
  1359. {
  1360.   struct tm *s;         /* result of localtime() */
  1361.  
  1362.   s = localtime(t);             /* Use local time since MSDOS does */
  1363.   inctime(s);                   /* Add one second to round up */
  1364.   return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
  1365.                  s->tm_hour, s->tm_min, s->tm_sec);
  1366. }
  1367.  
  1368.  
  1369. ulg filetime(f, a, n)
  1370. char *f;                /* name of file to get info on */
  1371. ulg *a;                 /* return value: file attributes */
  1372. long *n;                /* return value: file size */
  1373. /* If file *f does not exist, return 0.  Else, return the file's last
  1374.    modified date and time as an MSDOS date and time.  The date and
  1375.    time is returned in a long with the date most significant to allow
  1376.    unsigned integer comparison of absolute times.  Also, if a is not
  1377.    a NULL pointer, store the file attributes there, with the high two
  1378.    bytes being the Unix attributes, and the low byte being a mapping
  1379.    of that to DOS attributes.  If n is not NULL, store the file size
  1380.    there. */
  1381. {
  1382.   struct stat s;        /* results of stat() */
  1383.  
  1384. #ifdef S_IFLNK
  1385.   if (linkput ? lstat(f, &s) == 0 && ((s.st_mode & S_IFMT) == S_IFREG ||
  1386.                                       (s.st_mode & S_IFMT) == S_IFLNK) :
  1387. #else /* !S_IFLNK */
  1388.   if (
  1389. #endif /* ?S_IFLNK */
  1390.                 stat(f, &s) == 0 && (s.st_mode & S_IFMT) == S_IFREG)
  1391.   {
  1392.     if (a != NULL)
  1393.       *a = (s.st_mode << 16) | !(s.st_mode & S_IWRITE);
  1394.     if (n != NULL)
  1395.       *n = s.st_size;
  1396. #ifdef VMS
  1397.     return unix2dostime(&s.st_ctime);   /* Use creation time in VMS */
  1398. #else /* !VMS */
  1399.     return unix2dostime(&s.st_mtime);
  1400. #endif /* ?VMS */
  1401.   }
  1402.   else
  1403.     return 0;
  1404. }
  1405.  
  1406.  
  1407. int issymlnk(a)
  1408. ulg a;                  /* Attributes returned by filetime() */
  1409. /* Return true if the attributes are those of a symbolic link */
  1410. {
  1411. #ifdef S_IFLNK
  1412.   return ((a >> 16) & S_IFMT) == S_IFLNK;
  1413. #else /* !S_IFLNK */
  1414.   return (int)a & 0;    /* avoid warning on unused parameter */
  1415. #endif /* ?S_IFLNK */
  1416. }
  1417.  
  1418.  
  1419. int deletedir(d)
  1420. char *d;                /* directory to delete */
  1421. /* Delete the (empty) directory *d.  Return the result of rmdir(), delete(),
  1422.    or system(). */
  1423. {
  1424. #ifdef RMDIR
  1425.   /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
  1426.   int r, len;
  1427.   char *s;              /* malloc'd string for system command */
  1428.  
  1429.   len = strlen(d);
  1430.   if ((s = malloc(len + 34)) == NULL)
  1431.     return 127;
  1432.  
  1433. #ifdef VMS
  1434.   {
  1435.     char *c;            /* pointer into VMS path */
  1436.     /* convert "DEV:[DIR.SUB1.SUB2]" form to "DEV:[DIR.SUB1]SUB2.DIR;0" */
  1437.     strcat(strcpy(s, "set prot=(o:rwed) "), d);   /* d starts at s+18 */
  1438.     if (*(c = s+17+len) != ']')
  1439.     {
  1440.       free(s);
  1441.       return 127;
  1442.     }
  1443.     strcpy(c, ".DIR;0");        /* 0 translates to highest version */
  1444.     while (--c > s+18  &&  *c != '.'  &&  *c != '[') ;
  1445.     if (c == s+18)
  1446.     {
  1447.       free(s);
  1448.       return 127;
  1449.     }
  1450.     if (*c == '.')
  1451.       *c = ']';
  1452.     else if (*--c == ']')  /* presumably of form "DEV:[DIR.SUB1.][SUB2]" */
  1453.     {                      /* (possible to have "DEV:[DIR.SUB1.][][SUB2]"?) */
  1454.       char *b = c + 2;
  1455.       c[-1] = ']';
  1456.       while (*c++ = *b++) ;
  1457.     }
  1458.     else        /* must have reached device name:  can't delete top level */
  1459.     {
  1460.       free(s);
  1461.       return 127;
  1462.     }
  1463.   }
  1464.   /* unprotect directory and delete it as a file.  May fail if exists 
  1465.      normal file "foo.dir" on top of directory "foo.dir" */
  1466.   system(s);
  1467.   r = delete(s+18);
  1468. #else /* !VMS */
  1469.   sprintf(s, "IFS=\" \t\n\" /bin/rmdir %s 2>/dev/null", d);
  1470.   r = system(s);
  1471. #endif /* ?VMS */
  1472.   free(s);
  1473.   return r;
  1474. #else /* !RMDIR */
  1475.   return rmdir(d);
  1476. #endif /* ?RMDIR */
  1477. }
  1478.  
  1479.  
  1480. #endif /* !UTIL */
  1481.  
  1482.  
  1483. int destroy(f)
  1484. char *f;                /* file to delete */
  1485. /* Delete the file *f, returning non-zero on failure. */
  1486. {
  1487.   return unlink(f);
  1488. }
  1489.  
  1490.  
  1491. int replace(d, s)
  1492. char *d, *s;            /* destination and source file names */
  1493. /* Replace file *d by file *s, removing the old *s.  Return an error code
  1494.    in the ZE_ class. */
  1495. {
  1496.   struct stat t;        /* results of stat() */
  1497.  
  1498.   if (stat(d, &t) == 0 && unlink(d))
  1499.     return ZE_CREAT;                    /* Can't erase zip file--give up */
  1500.   if (link(s, d))                       /* Just move s on top of d */
  1501. #ifndef VMS                             /* For VMS, assume failure is EXDEV */
  1502.     if (errno != EXDEV)
  1503.       return ZE_CREAT;
  1504.     else
  1505. #endif /* !VMS */
  1506.     {
  1507.       FILE *f, *g;      /* source and destination files */
  1508.       int r;            /* temporary variable */
  1509.  
  1510.       if ((f = fopen(s, FOPR)) == NULL)
  1511.         return ZE_TEMP;
  1512.       if ((g = fopen(d, FOPW)) == NULL)
  1513.       {
  1514.         fclose(f);
  1515.         return ZE_CREAT;
  1516.       }
  1517.       r = fcopy(f, g, (ulg)-1L);
  1518.       fclose(f);
  1519.       if (fclose(g) || r != ZE_OK)
  1520.       {
  1521.         unlink(d);
  1522.         return r ? (r == ZE_TEMP ? ZE_WRITE : r) : ZE_WRITE;
  1523.       }
  1524. #ifdef VMS /* only delete if rename failed:  previous version may exist */
  1525.       unlink(s);
  1526.     }
  1527. #else /* !VMS */
  1528.     }
  1529.   unlink(s);
  1530. #endif /* !VMS */
  1531.   return ZE_OK;
  1532. }
  1533.  
  1534.  
  1535. int getfileattr(f)
  1536. char *f;                /* file path */
  1537. /* Return the file attributes for file f or -1 if failure */
  1538. {
  1539.   struct stat s;
  1540.  
  1541.   return stat(f, &s) == 0 ? s.st_mode : 0;
  1542. }
  1543.  
  1544.  
  1545. int setfileattr(f, a)
  1546. char *f;                /* file path */
  1547. int a;                  /* attributes returned by getfileattr() */
  1548. /* Give the file f the attributes a, return non-zero on failure */
  1549. {
  1550. #ifdef VMS
  1551.   return 0;
  1552. #else /* !VMS */
  1553.   return chmod(f, a);
  1554. #endif /* ?VMS */
  1555. }
  1556.  
  1557.  
  1558. char *tempname(c)
  1559. int c;                  /* character to insert in name */
  1560. /* Return a temporary file name in its own malloc'ed space, using tempath. */
  1561. {
  1562.   char *p;              /* temporary pointer */
  1563.   char *t;              /* malloc'ed space for name */
  1564.   
  1565.   if (tempath != NULL)
  1566.   {
  1567.     if ((t = malloc(strlen(tempath)+10)) == NULL)
  1568.       return NULL;
  1569.     strcpy(t, tempath);
  1570.     if (t[strlen(t)-1] != '/')
  1571.       strcat(t, "/");
  1572.   }
  1573.   else
  1574.   {
  1575.     if ((t = malloc(9)) == NULL)
  1576.       return NULL;
  1577.     *t = 0;
  1578.   }
  1579.   p = t + strlen(t);
  1580.   *p++ = '_';
  1581.   *p++ = (char)c;
  1582.   strcpy(p, "XXXXXX");
  1583.   return mktemp(t);
  1584. }
  1585.  
  1586.  
  1587. int fcopy(f, g, n)
  1588. FILE *f, *g;            /* source and destination files */
  1589. ulg n;                  /* number of bytes to copy or -1 for all */
  1590. /* Copy n bytes from file *f to file *g, or until EOF if n == -1.  Return
  1591.    an error code in the ZE_ class. */
  1592. {
  1593.   char *b;              /* malloc'ed buffer for copying */
  1594.   extent k;             /* result of fread() */
  1595.   ulg m;                /* bytes copied so far */
  1596.  
  1597.   if ((b = malloc(BSZ)) == NULL)
  1598.     return ZE_MEM;
  1599.   m = 0;
  1600.   while (n == -1L || m < n)
  1601.   {
  1602.     if ((k = fread(b, 1, n == -1 ?
  1603.                    BSZ : (n - m < BSZ ? (extent)(n - m) : BSZ), f)) == 0)
  1604.       if (ferror(f))
  1605.       {
  1606.         free((voidp *)b);
  1607.         return ZE_READ;
  1608.       }
  1609.       else
  1610.         break;
  1611.     if (fwrite(b, 1, k, g) != k)
  1612.     {
  1613.       free((voidp *)b);
  1614.       return ZE_TEMP;
  1615.     }
  1616.     m += k;
  1617.   }
  1618.   free((voidp *)b);
  1619.   return ZE_OK;
  1620. }
  1621.  
  1622.  
  1623. #ifndef EXPORT
  1624.  
  1625. #ifndef MSVMS
  1626.  
  1627. local int echofd = -1;  /* file descriptor whose echo is off */
  1628.  
  1629. void echoff(f)
  1630. int f;                  /* file descriptor to turn echo off on */
  1631. /* Turn echo off for file descriptor f.  Assumes that f is a tty device. */
  1632. {
  1633.   struct sgttyb sg;     /* tty device structure */
  1634.  
  1635.   echofd = f;
  1636.   GTTY(f, &sg);                                 /* get settings */
  1637.   sg.sg_flags &= ~ECHO;                         /* turn echo off */
  1638.   STTY(f, &sg);
  1639. }
  1640.  
  1641. void echon()
  1642. /* Turn echo back on for file descriptor echofd. */
  1643. {
  1644.   struct sgttyb sg;     /* tty device structure */
  1645.  
  1646.   if (echofd != -1)
  1647.   {
  1648.     GTTY(echofd, &sg);                          /* get settings */
  1649.     sg.sg_flags |= ECHO;                        /* turn echo on */
  1650.     STTY(echofd, &sg);
  1651.     echofd = -1;
  1652.   }
  1653. }
  1654.  
  1655. #endif /* !MSVMS */
  1656.  
  1657.  
  1658. char *getp(m, p, n)
  1659. char *m;                /* prompt for password */
  1660. char *p;                /* return value: line input */
  1661. int n;                  /* bytes available in p[] */
  1662. /* Get a password of length n-1 or less into *p using the prompt *m.
  1663.    The entered password is not echoed.  Return p on success, NULL on
  1664.    failure (can't get controlling tty). */
  1665. {
  1666.   char c;               /* one-byte buffer for read() to use */
  1667.   int i;                /* number of characters input */
  1668.   char *w;              /* warning on retry */
  1669.  
  1670. #ifndef MSVMS
  1671.   int f;                /* file decsriptor for tty device */
  1672.  
  1673.   /* Turn off echo on tty */
  1674.   if (!isatty(2))
  1675.     return NULL;                                /* error if not tty */
  1676.   if ((f = open(ttyname(2), 0, 0)) == -1)
  1677.     return NULL;
  1678.   echoff(f);                                    /* turn echo off */
  1679. #endif /* !MSVMS */
  1680.  
  1681.   /* Get password */
  1682.   w = "";
  1683.   do {
  1684.     fputs(w, stderr);                           /* warning if back again */
  1685.     fputs(m, stderr);                           /* prompt */
  1686.     fflush(stderr);
  1687.     i = 0;
  1688.     do {                                        /* read line, keeping n */
  1689. #ifdef MSVMS
  1690.       if ((c = (char)getch()) == '\r')
  1691.         c = '\n';
  1692. #else /* !MSVMS */
  1693.       read(f, &c, 1);
  1694. #endif /* ?MSVMS */
  1695.       if (i < n)
  1696.         p[i++] = c;
  1697.     } while (c != '\n');
  1698.     putc('\n', stderr);  fflush(stderr);
  1699.     w = "(line too long--try again)\n";
  1700.   } while (p[i-1] != '\n');
  1701.   p[i-1] = 0;                                   /* terminate at newline */
  1702.  
  1703. #ifndef MSVMS
  1704.   /* Turn echo back on */
  1705.   echon();                                      /* turn echo back on */
  1706.   close(f);
  1707. #endif /* !MSVMS */
  1708.  
  1709.   /* Return pointer to password */
  1710.   return p;
  1711. }
  1712.  
  1713. #endif /* !EXPORT */
  1714.  
  1715.  
  1716. #ifdef ZMEM
  1717.  
  1718. /************************/
  1719. /*  Function memset()  */
  1720. /************************/
  1721.  
  1722. /*
  1723.  * memset - for systems without it
  1724.  *  bill davidsen - March 1990
  1725.  */
  1726.  
  1727. char *
  1728. memset(buf, init, len)
  1729. register char *buf;     /* buffer loc */
  1730. register int init;      /* initializer */
  1731. register unsigned int len;   /* length of the buffer */
  1732. {
  1733.     char *start;
  1734.  
  1735.     start = buf;
  1736.     while (len--) *(buf++) = init;
  1737.     return(start);
  1738. }
  1739.  
  1740.  
  1741. /************************/
  1742. /*  Function memcpy()  */
  1743. /************************/
  1744.  
  1745. char *
  1746. memcpy(dst,src,len)           /* v2.0f */
  1747. register char *dst, *src;
  1748. register unsigned int len;
  1749. {
  1750.     char *start;
  1751.  
  1752.     start = dst;
  1753.     while (len--)
  1754.         *dst++ = *src++;
  1755.     return(start);
  1756. }
  1757.  
  1758.  
  1759. /************************/
  1760. /*  Function memcmp()  */
  1761. /************************/
  1762.  
  1763. int
  1764. memcmp(b1,b2,len)                     /* jpd@usl.edu -- 11/16/90 */
  1765. register char *b1, *b2;
  1766. register unsigned int len;
  1767. {
  1768.  
  1769.     if (len) do {             /* examine each byte (if any) */
  1770.       if (*b1++ != *b2++)
  1771.         return (*--((uch *)b1) - *--((uch *)b2));  /* exit when miscompare */
  1772.        } while (--len);
  1773.  
  1774.     return(0);        /* no miscompares, yield 0 result */
  1775. }
  1776.  
  1777. #endif  /* ZMEM */
  1778.